home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, John F. Haugh II
- * All rights reserved.
- *
- * Permission is granted to copy and create derivative works for any
- * non-commercial purpose, provided this copyright notice is preserved
- * in all copies of source code, or included in human readable form
- * and conspicuously displayed on all copies of object code or
- * distribution media.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)usermod.c 3.9 13:22:39 3/9/92";
- #endif
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <errno.h>
- #include "pwd.h"
- #include <grp.h>
- #include <ctype.h>
- #include <fcntl.h>
- #include <time.h>
-
- #ifdef BSD
- #include <strings.h>
- #else
- #include <string.h>
- #endif
-
- #include "config.h"
- #include "shadow.h"
- #include "faillog.h"
- #include <lastlog.h>
-
- #ifdef USE_SYSLOG
- #include <syslog.h>
-
- #ifndef LOG_WARN
- #define LOG_WARN LOG_WARNING
- #endif
- #endif
-
- #ifndef NGROUPS_MAX
- #define NGROUPS_MAX 64
- #endif
-
- #define VALID(s) (strcspn (s, ":\n") == strlen (s))
-
- char user_name[BUFSIZ];
- char user_newname[BUFSIZ];
- uid_t user_id;
- uid_t user_newid;
- gid_t user_gid;
- char user_comment[BUFSIZ];
- char user_home[BUFSIZ];
- char user_newhome[BUFSIZ];
- char user_shell[BUFSIZ];
- long user_expire;
- long user_inactive;
- int user_ngroups = -1;
- gid_t user_groups[NGROUPS_MAX];
- struct passwd user_pwd;
- struct spwd user_spwd;
-
- char *Prog;
-
- int uflg; /* specify user ID for new account */
- int oflg; /* permit non-unique user ID to be specified with -u */
- int gflg; /* primary group ID for new account */
- int Gflg; /* secondary group set for new account */
- int dflg; /* home directory for new account */
- int sflg; /* shell program for new account */
- int cflg; /* comment (GECOS) field for new account */
- int mflg; /* create user's home directory if it doesn't exist */
- int fflg; /* days until account with expired password is locked */
- int eflg; /* days after password changed before it becomes expired */
- int lflg; /* new user name for user */
-
- #ifdef NDBM
- extern int pw_dbm_mode;
- extern int sp_dbm_mode;
- extern int gr_dbm_mode;
- #ifdef SHADOWGRP
- extern int sg_dbm_mode;
- #endif
- #endif
- extern FILE *fopen();
- extern int fclose();
- extern char *malloc();
- extern char *mktemp();
-
- extern struct group *getgrnam();
- extern struct group *getgrgid();
- extern struct group *gr_next();
- extern struct group *gr_locate();
- extern int gr_lock();
- extern int gr_unlock();
- extern int gr_rewind();
- extern int gr_open();
-
- #ifdef SHADOWGRP
- extern struct sgrp *sgr_next();
- extern int sgr_lock();
- extern int sgr_unlock();
- extern int sgr_rewind();
- extern int sgr_open();
- #endif
-
- extern struct passwd *getpwnam();
- extern struct passwd *pw_next();
- extern struct passwd *pw_locate();
- extern int pw_lock();
- extern int pw_unlock();
- extern int pw_rewind();
- extern int pw_open();
-
- extern int spw_lock();
- extern int spw_unlock();
- extern int spw_open();
- extern struct spwd *spw_locate();
-
- #define DAY (24L*3600L)
- #define WEEK (7*DAY)
-
- #ifdef ITI_AGING
- #define SCALE (1)
- #else
- #define SCALE (DAY)
- #endif
-
- /*
- * days and juldays are used to compute the number of days in the
- * current month, and the cummulative number of days in the preceding
- * months. they are declared so that january is 1, not 0.
- */
-
- static short days[13] = { 0,
- 31, 28, 31, 30, 31, 30, /* JAN - JUN */
- 31, 31, 30, 31, 30, 31 }; /* JUL - DEC */
-
- static short juldays[13] = { 0,
- 0, 31, 59, 90, 120, 151, /* JAN - JUN */
- 181, 212, 243, 273, 304, 334 }; /* JUL - DEC */
-
- #ifdef NEED_RENAME
- /*
- * rename - rename a file to another name
- *
- * rename is provided for systems which do not include the rename()
- * system call.
- */
-
- int
- rename (begin, end)
- char *begin;
- char *end;
- {
- struct stat s1, s2;
- extern int errno;
- int orig_err = errno;
-
- if (stat (begin, &s1))
- return -1;
-
- if (stat (end, &s2)) {
- errno = orig_err;
- } else {
-
- /*
- * See if this is a cross-device link. We do this to
- * insure that the link below has a chance of working.
- */
-
- if (s1.st_dev != s2.st_dev) {
- errno = EXDEV;
- return -1;
- }
-
- /*
- * See if we can unlink the existing destination
- * file. If the unlink works the directory is writable,
- * so there is no need here to figure that out.
- */
-
- if (unlink (end))
- return -1;
- }
-
- /*
- * Now just link the original name to the final name. If there
- * was no file previously, this link will fail if the target
- * directory isn't writable. The unlink will fail if the source
- * directory isn't writable, but life stinks ...
- */
-
- if (link (begin, end) || unlink (begin))
- return -1;
-
- return 0;
- }
- #endif
-
- /*
- * strtoday - compute the number of days since 1970.
- *
- * the total number of days prior to the current date is
- * computed. january 1, 1970 is used as the origin with
- * it having a day number of 0.
- */
-
- long
- strtoday (str)
- char *str;
- {
- char slop[2];
- int month;
- int day;
- int year;
- long total;
-
- /*
- * start by separating the month, day and year. this is
- * a chauvanistic program - it only takes date input in
- * the standard USA format.
- */
-
- if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
- return -1;
-
- /*
- * the month, day of the month, and year are checked for
- * correctness and the year adjusted so it falls between
- * 1970 and 2069.
- */
-
- if (month < 1 || month > 12)
- return -1;
-
- if (day < 1)
- return -1;
-
- if ((month != 2 || (year % 4) != 0) && day > days[month])
- return -1;
- else if ((month == 2 && (year % 4) == 0) && day > 29)
- return -1;
-
- if (year < 0)
- return -1;
- else if (year < 69)
- year += 2000;
- else if (year < 99)
- year += 1900;
-
- if (year < 1970 || year > 2069)
- return -1;
-
- /*
- * the total number of days is the total number of days in all
- * the whole years, plus the number of leap days, plus the
- * number of days in the whole months preceding, plus the number
- * of days so far in the month.
- */
-
- total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
- total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
- total += (long) day - 1;
-
- return total;
- }
-
- /*
- * add_list - add a member to a list of group members
- *
- * the array of member names is searched for the new member
- * name, and if not present it is added to a freshly allocated
- * list of users.
- */
-
- char **
- add_list (list, member)
- char **list;
- char *member;
- {
- int i;
- char **tmp;
-
- /*
- * Scan the list for the new name. Return the original list
- * pointer if it is present.
- */
-
- for (i = 0;list[i] != (char *) 0;i++)
- if (strcmp (list[i], member) == 0)
- return list;
-
- /*
- * Allocate a new list pointer large enough to hold all the
- * old entries, and the new entries as well.
- */
-
- if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
- return 0;
-
- /*
- * Copy the original list to the new list, then append the
- * new member and NULL terminate the result. This new list
- * is returned to the invoker.
- */
-
- for (i = 0;list[i] != (char *) 0;i++)
- tmp[i] = list[i];
-
- tmp[i++] = strdup (member);
- tmp[i] = (char *) 0;
-
- return tmp;
- }
-
- /*
- * del_list - delete a member from a list of group members
- *
- * the array of member names is searched for the old member
- * name, and if present it is deleted from a freshly allocated
- * list of users.
- */
-
- char **
- del_list (list, member)
- char **list;
- char *member;
- {
- int i, j;
- char **tmp;
-
- /*
- * Scan the list for the new name. Return the original list
- * pointer if it is present.
- */
-
- for (i = j = 0;list[i] != (char *) 0;i++)
- if (strcmp (list[i], member))
- j++;
-
- if (j == i)
- return list;
-
- /*
- * Allocate a new list pointer large enough to hold all the
- * old entries, and the new entries as well.
- */
-
- if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
- return 0;
-
- /*
- * Copy the original list to the new list, then append the
- * new member and NULL terminate the result. This new list
- * is returned to the invoker.
- */
-
- for (i = j = 0;list[i] != (char *) 0;i++)
- if (strcmp (list[i], member))
- tmp[j++] = list[i];
-
- tmp[j] = (char *) 0;
-
- return tmp;
- }
-
- /*
- * get_groups - convert a list of group names to an array of group IDs
- *
- * get_groups() takes a comma-separated list of group names and
- * converts it to an array of group ID values. Any unknown group
- * names are reported as errors.
- */
-
- int
- get_groups (list)
- char *list;
- {
- char *cp;
- struct group *grp;
- int errors = 0;
-
- /*
- * Initialize the list to be empty
- */
-
- user_ngroups = 0;
-
- if (! *list)
- return 0;
-
- /*
- * So long as there is some data to be converted, strip off
- * each name and look it up. A mix of numerical and string
- * values for group identifiers is permitted.
- */
-
- do {
- /*
- * Strip off a single name from the list
- */
-
- if (cp = strchr (list, ','))
- *cp++ = '\0';
-
- /*
- * Names starting with digits are treated as numerical
- * GID values, otherwise the string is looked up as is.
- */
-
- if (isdigit (*list))
- grp = getgrgid (atoi (list));
- else
- grp = getgrnam (list);
-
- /*
- * There must be a match, either by GID value or by
- * string name.
- */
-
- if (! grp) {
- fprintf (stderr, "%s: unknown group %s\n", Prog, list);
- errors++;
- }
-
- /*
- * Add the GID value from the group file to the user's
- * list of groups.
- */
-
- user_groups[user_ngroups++] = grp->gr_gid;
-
- list = cp;
- } while (list);
-
- /*
- * Any errors in finding group names are fatal
- */
-
- if (errors)
- return -1;
-
- return 0;
- }
-
- /*
- * usage - display usage message and exit
- */
-
- usage ()
- {
- fprintf (stderr,
- "usage: %s [-u uid [-o]] [-g group] [-G group,...] \n", Prog);
- fprintf (stderr,
- "\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n");
- fprintf (stderr,
- "\t\t[-f inactive] [-e expire] name\n");
-
- exit (2);
- }
-
- /*
- * new_pwent - initialize the values in a password file entry
- *
- * new_pwent() takes all of the values that have been entered and
- * fills in a (struct passwd) with them.
- */
-
- void
- new_pwent (pwent)
- struct passwd *pwent;
- {
- if (lflg) {
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change user name `%s' to `%s'\n",
- pwent->pw_name, user_newname);
- #endif
- pwent->pw_name = strdup (user_newname);
- }
- if (uflg) {
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change user `%s' UID from `%d' to `%d'\n",
- pwent->pw_name, pwent->pw_uid, user_newid);
- #endif
- pwent->pw_uid = user_newid;
- }
- if (gflg) {
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change user `%s' GID from `%d' to `%d'\n",
- pwent->pw_name, pwent->pw_gid, user_gid);
- #endif
- pwent->pw_gid = user_gid;
- }
- if (cflg)
- pwent->pw_gecos = strdup (user_comment);
-
- if (dflg) {
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change user `%s' home from `%s' to `%s'\n",
- pwent->pw_name, pwent->pw_dir, user_newhome);
- #endif
- pwent->pw_dir = strdup (user_newhome);
- }
- if (sflg) {
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change user `%s' shell from `%s' to `%s'\n",
- pwent->pw_name, pwent->pw_shell, user_shell);
- #endif
- pwent->pw_shell = strdup (user_shell);
- }
- }
-
- /*
- * new_spent - initialize the values in a shadow password file entry
- *
- * new_spent() takes all of the values that have been entered and
- * fills in a (struct spwd) with them.
- */
-
- void
- new_spent (spent)
- struct spwd *spent;
- {
- if (lflg)
- spent->sp_namp = strdup (user_newname);
-
- if (fflg) {
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change user `%s' inactive from `%d' to `%d'\n",
- spent->sp_namp, spent->sp_inact, user_inactive);
- #endif
- spent->sp_inact = user_inactive;
- }
- if (eflg) {
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change user `%s' expiration from `%d' to `%d'\n",
- spent->sp_namp, spent->sp_expire, user_expire);
- #endif
- spent->sp_expire = user_expire;
- }
- }
-
- /*
- * grp_update - add user to secondary group set
- *
- * grp_update() takes the secondary group set given in user_groups
- * and adds the user to each group given by that set.
- */
-
- void
- grp_update ()
- {
- int i;
- int is_member;
- int was_member;
- struct group *grp;
- #ifdef SHADOWGRP
- int was_admin;
- struct sgrp *sgrp;
- #endif
-
- /*
- * Lock and open the group file. This will load all of the group
- * entries.
- */
-
- if (! gr_lock ()) {
- fprintf (stderr, "%s: error locking group file\n", Prog);
- exit (1);
- }
- if (! gr_open (O_RDWR)) {
- fprintf (stderr, "%s: error opening group file\n", Prog);
- exit (1);
- }
- #ifdef SHADOWGRP
- if (! sgr_lock ()) {
- fprintf (stderr, "%s: error locking shadow group file\n", Prog);
- exit (1);
- }
- if (! sgr_open (O_RDWR)) {
- fprintf (stderr, "%s: error opening shadow group file\n", Prog);
- exit (1);
- }
- #endif
-
- /*
- * Scan through the entire group file looking for the groups that
- * the user is a member of.
- */
-
- for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
-
- /*
- * See if the user specified this group as one of their
- * concurrent groups.
- */
-
- for (i = 0;i < user_ngroups;i++)
- if (grp->gr_gid == user_groups[i])
- break;
-
- is_member = i == user_ngroups ? -1:i;
-
- for (i = 0;grp->gr_mem[i];i++)
- if (strcmp (user_name, grp->gr_mem[i]) == 0)
- break;
-
- was_member = grp->gr_mem[i] ? i:-1;
-
- if (is_member == -1 && was_member == -1)
- continue;
-
- if (was_member >= 0 && (! Gflg || is_member >= 0)) {
- if (lflg) {
- grp->gr_mem = del_list (grp->gr_mem,
- user_name);
- grp->gr_mem = add_list (grp->gr_mem,
- user_newname);
- #ifdef USE_SYSLOG
- syslog (LOG_INFO,
- "change `%s' to `%s' in group `%s'\n",
- user_name, user_newname, grp->gr_name);
- #endif
- }
- } else if (was_member >= 0 && Gflg && is_member < 0) {
- grp->gr_mem = del_list (grp->gr_mem, user_name);
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "delete `%s' from group `%s'\n",
- user_name, grp->gr_name);
- #endif
- } else if (was_member < 0 && Gflg && is_member >= 0) {
- grp->gr_mem = add_list (grp->gr_mem,
- lflg ? user_newname:user_name);
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "add `%s' to group `%s'\n",
- lflg ? user_newname:user_name, grp->gr_name);
- #endif
- } else
- continue;
-
- if (! gr_update (grp)) {
- fprintf (stderr, "%s: error adding new group entry\n",
- Prog);
- exit (1);
- }
- #ifdef NDBM
- /*
- * Update the DBM group file with the new entry as well.
- */
-
- if (! gr_dbm_update (grp)) {
- fprintf (stderr, "%s: cannot add new dbm group entry\n",
- Prog);
- exit (1);
- }
- endgrent ();
- #endif
- }
-
- #ifdef SHADOWGRP
- /*
- * Scan through the entire shadow group file looking for the groups
- * that the user is a member of.
- */
-
- for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
-
- /*
- * See if the user was a member of this group
- */
-
- for (i = 0;sgrp->sg_mem[i];i++)
- if (strcmp (sgrp->sg_mem[i], user_name) == 0)
- break;
-
- was_member = sgrp->sg_mem[i] ? i:-1;
-
- /*
- * See if the user was an administrator of this group
- */
-
- for (i = 0;sgrp->sg_adm[i];i++)
- if (strcmp (sgrp->sg_adm[i], user_name) == 0)
- break;
-
- was_admin = sgrp->sg_adm[i] ? i:-1;
-
- /*
- * See if the user specified this group as one of their
- * concurrent groups.
- */
-
- for (i = 0;i < user_ngroups;i++) {
- if (! (grp = gr_locate (sgrp->sg_name)))
- continue;
-
- if (grp->gr_gid == user_groups[i])
- break;
- }
- is_member = i == user_ngroups ? -1:i;
-
- if (is_member == -1 && was_admin == -1 && was_member == -1)
- continue;
-
- if (was_admin >= 0 && lflg) {
- sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
- sgrp->sg_adm = add_list (sgrp->sg_adm, user_newname);
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change admin `%s' to `%s' in shadow group `%s'\n",
- user_name, user_newname, sgrp->sg_name);
- #endif
- }
- if (was_member >= 0 && (! Gflg || is_member >= 0)) {
- if (lflg) {
- sgrp->sg_mem = del_list (sgrp->sg_mem,
- user_name);
- sgrp->sg_mem = add_list (sgrp->sg_mem,
- user_newname);
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "change `%s' to `%s' in shadow group `%s'\n",
- user_name, user_newname, sgrp->sg_name);
- #endif
- }
- } else if (was_member >= 0 && Gflg && is_member < 0) {
- sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "delete `%s' from shadow group `%s'\n",
- user_name, sgrp->sg_name);
- #endif
- } else if (was_member < 0 && Gflg && is_member >= 0) {
- sgrp->sg_mem = add_list (sgrp->sg_mem,
- lflg ? user_newname:user_name);
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
- lflg ? user_newname:user_name, grp->gr_name);
- #endif
- } else
- continue;
-
- /*
- * Update the group entry to reflect the changes.
- */
-
- if (! sgr_update (sgrp)) {
- fprintf (stderr, "%s: error adding new group entry\n",
- Prog);
- exit (1);
- }
- #ifdef NDBM
- /*
- * Update the DBM group file with the new entry as well.
- */
-
- if (! sgr_dbm_update (sgrp)) {
- fprintf (stderr, "%s: cannot add new dbm group entry\n",
- Prog);
- exit (1);
- }
- endsgent ();
- #endif
- }
- #endif
- }
-
- /*
- * check_new_id - verify the new UID for uniqueness
- *
- * check_new_id() insures that the new UID does not exist already.
- * It does this by checking that the UID has changed and that there
- * is no current entry for this user ID.
- */
-
- int
- check_new_id ()
- {
- /*
- * First, the easy stuff. If the ID can be duplicated, or if
- * the ID didn't really change, just return. If the ID didn't
- * change, turn off those flags. No sense doing needless work.
- */
-
- if (oflg)
- return 0;
-
- if (user_id == user_newid) {
- uflg = lflg = 0;
- return 0;
- }
- if (getpwuid (user_newid))
- return -1;
-
- return 0;
- }
-
- /*
- * process_flags - perform command line argument setting
- *
- * process_flags() interprets the command line arguments and sets
- * the values that the user will be created with accordingly. The
- * values are checked for sanity.
- */
-
- void
- process_flags (argc, argv)
- int argc;
- char **argv;
- {
- extern int optind;
- extern char *optarg;
- struct group *grp;
- struct passwd *pwd;
- struct spwd *spwd;
- long l;
- int anyflag = 0;
- int arg;
-
- if (argc == 1 || argv[argc - 1][0] == '-')
- usage ();
-
- if (! (pwd = getpwnam (argv[argc - 1]))) {
- fprintf (stderr, "%s: user %s does not exist\n",
- Prog, argv[argc - 1]);
- exit (6);
- }
- strcpy (user_name, pwd->pw_name);
- user_id = pwd->pw_uid;
- user_gid = pwd->pw_gid;
- strcpy (user_comment, pwd->pw_gecos);
- strcpy (user_home, pwd->pw_dir);
- strcpy (user_shell, pwd->pw_shell);
-
- if (spwd = getspnam (user_name)) {
- user_expire = spwd->sp_expire;
- user_inactive = spwd->sp_inact;
- }
- while ((arg = getopt (argc, argv, "u:og:G:d:s:c:mf:e:l:")) != EOF) {
- switch (arg) {
- case 'c':
- if (! VALID (optarg)) {
- fprintf (stderr,
- "%s: invalid field `%s'\n",
- Prog, optarg);
- exit (3);
- }
- if (strcmp (optarg, user_comment)) {
- cflg++;
- strncpy (user_comment, optarg, BUFSIZ);
- }
- break;
- case 'd':
- if (! VALID (optarg)) {
- fprintf (stderr,
- "%s: invalid field `%s'\n",
- Prog, optarg);
- exit (3);
- }
- dflg++;
- strncpy (user_newhome, optarg, BUFSIZ);
- break;
- case 'e':
- l = strtoday (optarg);
- #ifdef ITI_AGING
- l *= DAY;
- #endif
- if (l != user_expire) {
- eflg++;
- user_expire = l;
- }
- break;
- case 'f':
- if (user_inactive != atoi (optarg)) {
- fflg++;
- user_inactive = atoi (optarg);
- }
- break;
- case 'g':
- if (isdigit (optarg[0]))
- grp = getgrgid (atoi (optarg));
- else
- grp = getgrnam (optarg);
-
- if (! grp) {
- fprintf (stderr,
- "%s: unknown group %s\n",
- Prog, optarg);
- exit (1);
- }
- if (grp->gr_gid != user_gid) {
- gflg++;
- user_gid = grp->gr_gid;
- }
- break;
- case 'G':
- Gflg++;
- if (get_groups (optarg))
- exit (1);
-
- break;
- case 'l':
- if (! VALID (optarg)) {
- fprintf (stderr,
- "%s: invalid field `%s'\n",
- Prog, optarg);
- exit (3);
- }
- if (strcmp (user_name, optarg)) {
- lflg++;
- strcpy (user_newname, optarg);
- }
- break;
- case 'm':
- if (! dflg)
- usage ();
-
- mflg++;
- break;
- case 'o':
- if (! uflg)
- usage ();
-
- oflg++;
- break;
- case 's':
- if (! VALID (optarg)) {
- fprintf (stderr,
- "%s: invalid field `%s'\n",
- Prog, optarg);
- exit (3);
- }
- if (strcmp (user_shell, optarg)) {
- strncpy (user_shell, optarg, BUFSIZ);
- sflg++;
- }
- break;
- case 'u':
- uflg++;
- user_newid = atoi (optarg);
- break;
- default:
- usage ();
- }
- anyflag++;
- }
- if (anyflag == 0) {
- fprintf (stderr, "%s: no flags given\n", Prog);
- exit (1);
- }
- if (optind != argc - 1)
- usage ();
-
- if (dflg && strcmp (user_home, user_newhome) == 0)
- dflg = mflg = 0;
-
- if (uflg && user_id == user_newid)
- uflg = oflg = 0;
-
- if (lflg && getpwnam (user_newname)) {
- fprintf (stderr, "%s: user %s exists\n", Prog, user_newname);
- exit (9);
- }
- }
-
- /*
- * close_files - close all of the files that were opened
- *
- * close_files() closes all of the files that were opened for this
- * new user. This causes any modified entries to be written out.
- */
-
- close_files ()
- {
- if (! pw_close ()) {
- fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
- exit (1);
- }
- if (! spw_close ()) {
- fprintf (stderr, "%s: cannot rewrite shadow password file\n",
- Prog);
- exit (1);
- }
- if (user_ngroups >= 0) {
- if (! gr_close ()) {
- fprintf (stderr, "%s: cannot rewrite group file\n",
- Prog);
- exit (1);
- }
- (void) gr_unlock ();
- #ifdef SHADOWGRP
- if (! sgr_close ()) {
- fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- Prog);
- exit (1);
- }
- (void) sgr_unlock ();
- #endif
- }
- (void) spw_unlock ();
- (void) pw_unlock ();
- }
-
- /*
- * open_files - lock and open the password files
- *
- * open_files() opens the two password files.
- */
-
- open_files ()
- {
- if (! pw_lock ()) {
- fprintf (stderr, "%s: unable to lock password file\n", Prog);
- exit (1);
- }
- if (! pw_open (O_RDWR)) {
- fprintf (stderr, "%s: unable to open password file\n", Prog);
- exit (1);
- }
- if (! spw_lock ()) {
- fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
- exit (1);
- }
- if (! spw_open (O_RDWR)) {
- fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
- exit (1);
- }
- }
-
- /*
- * usr_update - create the user entries
- *
- * usr_update() creates the password file entries for this user
- * and will update the group entries if required.
- */
-
- usr_update ()
- {
- struct passwd pwent;
- struct spwd spent;
- struct passwd *pwd;
- struct spwd *spwd;
-
- pwd = pw_locate (user_name);
- pwent = *pwd;
-
- spwd = spw_locate (user_name);
- spent = *spwd;
-
- new_pwent (&pwent);
- new_spent (&spent);
-
- if (lflg || uflg || gflg || cflg || dflg || sflg) {
- if (! pw_update (&pwent)) {
- fprintf (stderr, "%s: error changing password entry\n",
- Prog);
- exit (1);
- }
- if (lflg && ! pw_remove (user_name)) {
- fprintf (stderr, "%s: error removing password entry\n",
- Prog);
- exit (1);
- }
- #if defined(DBM) || defined(NDBM)
- if (access ("/etc/passwd.pag", 0) == 0) {
- if (! pw_dbm_update (&pwent)) {
- fprintf (stderr, "%s: error adding password dbm entry\n",
- Prog);
- exit (1);
- }
- if (lflg && (pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd)) {
- fprintf (stderr, "%s: error removing passwd dbm entry\n",
- Prog);
- exit (1);
- }
- endpwent ();
- }
- #endif
- }
- if (lflg || eflg || fflg) {
- if (! spw_update (&spent)) {
- fprintf (stderr, "%s: error adding new shadow password entry\n",
- Prog);
- exit (1);
- }
- if (lflg && ! spw_remove (user_name)) {
- fprintf (stderr, "%s: error removing shadow password entry\n",
- Prog);
- exit (1);
- }
- }
- #ifdef NDBM
- if (access ("/etc/shadow.pag", 0) == 0) {
- if (! sp_dbm_update (&spent)) {
- fprintf (stderr, "%s: error updating shadow passwd dbm entry\n",
- Prog);
- exit (1);
- }
- if (lflg && ! sp_dbm_remove (user_name)) {
- fprintf (stderr, "%s: error removing shadow passwd db entry\n",
- Prog);
- exit (1);
- }
- endspent ();
- }
- #endif
- if (Gflg || lflg)
- grp_update ();
- }
-
- /*
- * move_home - move the user's home directory
- *
- * move_home() moves the user's home directory to a new location.
- * The files will be copied if the directory cannot simply be
- * renamed.
- */
-
- move_home ()
- {
- struct stat sb;
-
- if (mflg && stat (user_home, &sb) == 0) {
- if (access (user_newhome, 0) == 0) {
- fprintf (stderr, "%s: directory %s exists\n",
- Prog, user_newhome);
- exit (12);
- } else if (rename (user_home, user_newhome)) {
- if (errno == EXDEV) {
- if (mkdir (user_newhome, sb.st_mode & 0777)) {
- fprintf (stderr,
- "%s: can't create %s\n",
- Prog, user_newhome);
- }
- chown (user_newhome, sb.st_uid, sb.st_gid);
- if (copy_tree (user_home, user_newhome,
- -1, -1) == 0 &&
- remove_tree (user_home) == 0 &&
- rmdir (user_home) == 0)
- return;
-
- remove_tree (user_newhome);
- rmdir (user_newhome);
- }
- fprintf (stderr,
- "%s: cannot rename directory %s to %s\n",
- Prog, user_home, user_newhome);
- exit (12);
- }
- }
- if (uflg || gflg)
- chown (dflg ? user_newhome:user_home, user_id, user_gid);
- }
-
- /*
- * update_files - update the lastlog and faillog files
- */
-
- update_files ()
- {
- struct lastlog ll;
- struct faillog fl;
- int fd;
-
- /*
- * Relocate the "lastlog" entries for the user. The old entry
- * is left alone in case the UID was shared. It doesn't hurt
- * anything to just leave it be.
- */
-
- if ((fd = open ("/usr/adm/lastlog", O_RDWR)) != -1) {
- lseek (fd, (long) user_id * sizeof ll, 0);
- if (read (fd, &ll, sizeof ll) == sizeof ll) {
- lseek (fd, (long) user_newid * sizeof ll, 0);
- write (fd, &ll, sizeof ll);
- }
- close (fd);
- }
-
- /*
- * Relocate the "faillog" entries in the same manner.
- */
-
- if ((fd = open (FAILFILE, O_RDWR)) != -1) {
- lseek (fd, (long) user_id * sizeof fl, 0);
- if (read (fd, &fl, sizeof fl) == sizeof fl) {
- lseek (fd, (long) user_newid * sizeof ll, 0);
- write (fd, &fl, sizeof fl);
- }
- close (fd);
- }
- }
-
- /*
- * main - usermod command
- */
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- /*
- * Get my name so that I can use it to report errors.
- */
-
- if (Prog = strrchr (argv[0], '/'))
- Prog++;
- else
- Prog = argv[0];
-
- #ifdef USE_SYSLOG
- openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- #endif
-
- /*
- * The open routines for the NDBM files don't use read-write
- * as the mode, so we have to clue them in.
- */
-
- #ifdef NDBM
- pw_dbm_mode = O_RDWR;
- sp_dbm_mode = O_RDWR;
- gr_dbm_mode = O_RDWR;
- #ifdef SHADOWGRP
- sg_dbm_mode = O_RDWR;
- #endif
- #endif
- process_flags (argc, argv);
-
- /*
- * Do the hard stuff - open the files, change the user entries,
- * change the home directory, then close and update the files.
- */
-
- open_files ();
-
- usr_update ();
-
- close_files ();
-
- if (mflg)
- move_home ();
-
- if (uflg)
- update_files ();
-
- exit (0);
- /*NOTREACHED*/
- }
-